package com.william.jdbcplus.core.dialect.ddl.util;

import com.william.jdbcplus.common.enums.DbType;
import com.william.jdbcplus.core.dialect.ddl.fk.FkFactory;
import com.william.jdbcplus.core.dialect.ddl.fk.IFk;
import com.william.jdbcplus.core.dialect.ddl.util.model.TableMeta;
import com.william.jdbcplus.core.meta.TableFkInfo;
import com.william.jdbcplus.core.meta.TableInfo;
import com.william.jdbcplus.core.util.JdbcExecUtil;
import com.william.jdbcplus.core.util.datameta.TableMetaFkInfo;

import javax.sql.DataSource;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 外键处理
 *
 * @author niliwei
 */
public class FkUtil {
    /**
     * 检查外键是否一致
     *
     * @param dbType    数据库类型
     * @param tableMeta 表信息
     * @return
     */
    public static List<String> check(DbType dbType, TableMeta tableMeta) {
        List<String> errList = new LinkedList<>();
        List<TableMetaFkInfo> metaFkInfos = tableMeta.getTableMeta().getFkList();
        Map<String, TableMetaFkInfo> fkInfoMap = metaFkInfos.stream().collect(Collectors.toMap(e -> e.getFkColumnName().toLowerCase(), e -> e));
        TableInfo tableInfo = tableMeta.getTableInfo();
        List<TableFkInfo> fkList = tableInfo.getFkList();
        IFk iFk = FkFactory.getInstance(dbType);
        for (TableFkInfo fk : fkList) {
            if (fkInfoMap.containsKey(fk.getFkColumnName().toLowerCase())) {
                TableMetaFkInfo fkInfo = fkInfoMap.get(fk.getFkColumnName().toLowerCase());
                // 数据表中外键已经存在而且与实例不一致, 则修改外键
                if (!iFk.match(tableMeta.getClazz(), fk, fkInfo)) {
                    errList.add("表 " + tableMeta.getTableInfo().getTableName() + " 中字段 " + fk.getFkColumnName() + " 关联表 " + fk.getPkTableName() + " 字段 " + fk.getPkColumnName() + " 外键不一致");
                }
            } else {
                // 数据表中外键不存在，则新增外键
                errList.add("表 " + tableMeta.getTableInfo().getTableName() + " 中字段 " + fk.getFkColumnName() + " 关联表 " + fk.getPkTableName() + " 字段 " + fk.getPkColumnName() + " 外键不存在");
            }
        }

        return errList;
    }

    /**
     * 更新外键结构
     *
     * @param dbType    数据库类型
     * @param tableMeta 实体表结构信息
     * @param ds        数据源
     * @return
     */
    public static void update(DbType dbType, TableMeta tableMeta, DataSource ds) {
        List<TableMetaFkInfo> metaFkInfos = tableMeta.getTableMeta().getFkList();
        Map<String, TableMetaFkInfo> fkInfoMap = metaFkInfos.stream().collect(Collectors.toMap(e -> e.getFkColumnName().toLowerCase(), e -> e));
        TableInfo tableInfo = tableMeta.getTableInfo();
        List<TableFkInfo> fkList = tableInfo.getFkList();
        IFk iFk = FkFactory.getInstance(dbType);
        for (TableFkInfo fk : fkList) {
            if (fkInfoMap.containsKey(fk.getFkColumnName().toLowerCase())) {
                TableMetaFkInfo fkInfo = fkInfoMap.get(fk.getFkColumnName().toLowerCase());
                // 数据表中外键已经存在而且与实例不一致, 则修改外键
                if (!iFk.match(tableMeta.getClazz(), fk, fkInfo)) {
                    String sql = iFk.modify(tableMeta.getClazz(), fk, fkInfo);
                    JdbcExecUtil.execOne(sql, ds);
                }
            } else {
                // 数据表中外键不存在，则新增外键
                String sql = iFk.add(tableMeta.getClazz(), fk);
                JdbcExecUtil.execOne(sql, ds);
            }
        }
    }

    /**
     * 获取外键更新脚本列表
     *
     * @param dbType
     * @param tableMeta
     */
    public static List<String> getUpdateSQL(DbType dbType, TableMeta tableMeta) {
        List<String> sqlList = new LinkedList<>();
        List<TableMetaFkInfo> metaFkInfos = tableMeta.getTableMeta().getFkList();
        Map<String, TableMetaFkInfo> fkInfoMap = metaFkInfos.stream().collect(Collectors.toMap(e -> e.getFkColumnName().toLowerCase(), e -> e));
        TableInfo tableInfo = tableMeta.getTableInfo();
        List<TableFkInfo> fkList = tableInfo.getFkList();
        IFk iFk = FkFactory.getInstance(dbType);
        for (TableFkInfo fk : fkList) {
            if (fkInfoMap.containsKey(fk.getFkColumnName().toLowerCase())) {
                TableMetaFkInfo fkInfo = fkInfoMap.get(fk.getFkColumnName().toLowerCase());
                // 数据表中外键已经存在而且与实例不一致, 则修改外键
                if (!iFk.match(tableMeta.getClazz(), fk, fkInfo)) {
                    String sql = iFk.modify(tableMeta.getClazz(), fk, fkInfo);
                    sqlList.add(sql);
                }
            } else {
                // 数据表中外键不存在，则新增外键
                String sql = iFk.add(tableMeta.getClazz(), fk);
                sqlList.add(sql);
            }
        }

        return sqlList;
    }
}
